#include <iostream>
#include <string>
#include <cerrno>
#include <string.h>
#include "RemoteInput.h"

using namespace Marco;

RemoteInput::RemoteInput()
{

}

RemoteInput::~RemoteInput()
{
   if(ioctl(mFD, UI_DEV_DESTROY) < 0)
   {
      std::string ex = "RemoteInput::~RemoteInput() Failed to destroy uinput file descriptor:\n";
      char errorMsg[128];
      ex += strerror_r(errno, errorMsg, 128);
      throw(ex);
   }
   close(mFD);
}

void RemoteInput::Initialize()
{
   mFD = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
   if(mFD < 0)
   {
      std::string ex = "RemoteInput::Initialize() Failed to open file desciptor to /dev/uinput:\n";
      char errorMsg[128];
      ex += strerror_r(errno, errorMsg, 128);
      throw(ex);
   }

   // initialize the uinput device
   ioctl(mFD, UI_SET_EVBIT, EV_KEY);
   ioctl(mFD, UI_SET_EVBIT, EV_REL);
   ioctl(mFD, UI_SET_EVBIT, EV_SYN);

   ioctl(mFD, UI_SET_RELBIT, REL_X);
   ioctl(mFD, UI_SET_RELBIT, REL_Y);
   ioctl(mFD, UI_SET_RELBIT, REL_WHEEL);

   ioctl(mFD, UI_SET_KEYBIT, BTN_MOUSE);
   ioctl(mFD, UI_SET_KEYBIT, BTN_LEFT);
   ioctl(mFD, UI_SET_KEYBIT, BTN_RIGHT);
   ioctl(mFD, UI_SET_KEYBIT, BTN_MIDDLE);

   // allow all keys to be sent to the device
   for(int i = 0; i < 256; ++i)
   {
      ioctl(mFD, UI_SET_KEYBIT, i);
   }

   bzero(&mUIDev, sizeof(mUIDev));

   snprintf(mUIDev.name, UINPUT_MAX_NAME_SIZE, "uinput-marco");
   mUIDev.id.bustype = BUS_USB;
   mUIDev.id.vendor  = 0x1;
   mUIDev.id.product = 0x1; 
   mUIDev.id.version = 1;
   //mUIDev.absmin[ABS_X] = 0;
   //mUIDev.absmax[ABS_X] = 1024;
   //mUIDev.absmin[ABS_Y] = 0;
   //mUIDev.absmax[ABS_Y] = 1024;

   if(write(mFD, &mUIDev, sizeof(mUIDev)) < 0)
   {
      std::string ex = "RemoteInput::Initialize() Failed to write to the file desciptor:\n";
      char errorMsg[128];
      ex += strerror_r(errno, errorMsg, 128);
      throw(ex);
   }

   if(ioctl(mFD, UI_DEV_CREATE) < 0)
   {
      std::string ex = "RemoteInput::Initialize() Failed to create device from file descriptor:\n";
      char errorMsg[128];
      ex += strerror_r(errno, errorMsg, 128);
      throw(ex);
   }
}

void RemoteInput::SendEvent(__u16 type, __u16 code, int value)
{
   struct timeval tod;
   gettimeofday(&tod, NULL);
   // Send event
   bzero(&mEvent, sizeof(struct input_event));
   mEvent.type = type;
   mEvent.code = code;
   mEvent.value = value;
   mEvent.time = tod;
   write(mFD, &mEvent, sizeof(mEvent));

   // Send synchronizer
   bzero(&mEvent, sizeof(struct input_event));
   mEvent.type = EV_SYN;
   mEvent.code = SYN_REPORT;
   mEvent.value = 0;
   mEvent.time = tod;
   write(mFD, &mEvent, sizeof(mEvent));
}

void RemoteInput::WriteKey(__u16 key, __u16 value)
{
   SendEvent(EV_KEY, key, value);
}

void RemoteInput::WriteMouse(int x, int y, int wheel)
{
   std::cout << "Sending mouse events: " << x << ", " << y << std::endl;
   SendEvent(EV_REL, REL_X, x);
   SendEvent(EV_REL, REL_Y, y);
   if(wheel != 0)
   {
      SendEvent(EV_REL, REL_WHEEL, wheel);
   }
}

